package cn.itsource.service.impl;


import cn.dev33.satoken.stp.StpUtil;
import cn.itsource.constants.Constants;
import cn.itsource.desktop.api.LoginApi;
import cn.itsource.desktop.pojo.param.LoginFound;
import cn.itsource.pojo.bo.DriverSettingBo;
import cn.itsource.pojo.domain.Driver;
import cn.itsource.mapper.DriverMapper;
import cn.itsource.pojo.domain.DriverSetting;
import cn.itsource.pojo.domain.DriverSummary;
import cn.itsource.pojo.dto.LocationDto;
import cn.itsource.pojo.dto.WxRegisterDto;
import cn.itsource.pojo.vo.DriverSummaryVo;
import cn.itsource.pojo.vo.WorkBenchDataVo;
import cn.itsource.result.JSONResult;
import cn.itsource.service.IDriverService;
import cn.itsource.service.IDriverSettingService;
import cn.itsource.service.IDriverSummaryService;
import cn.itsource.service.IDriverWalletService;
import cn.itsource.template.WxTemplate;
import cn.itsource.utils.AssertUtil;
import cn.itsource.utils.BitStatesUtils;


import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;


import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.data.geo.Point;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;


import java.util.Date;

/**
 * <p>
 * 司机对象 服务实现类
 * </p>
 *
 * @author ????
 * @since 2024-06-13
 */
@Service
@Slf4j
public class DriverServiceImpl extends ServiceImpl<DriverMapper, Driver> implements IDriverService {
    @Autowired
    private IDriverWalletService walletService;
    @Autowired
    private IDriverSettingService settingService;
    @Autowired
    private IDriverSummaryService summaryService;

    @Autowired
    private RedisTemplate<Object,Object> redisTemplate;

    @Autowired
    private WxTemplate wxTemplate;

    @Autowired
    private LoginApi loginApi;
    /**
     * 微信注册
     * 1.先获取参数，code，小程序ID，小程序秘钥
     * 2.拼接URL，组装参数，发送http请求（可以用restTemplate）
     * 3.拿到结果，获取openid
     * 4.判断；openid是否存在，如果存在就提示已注册
     * 5.openid不存在就保存司机对象，并初始化关联对象，如钱包，设置，结算
     * 6.远程保存login对象
     *
     * @param dto；参数对象，包括微信code
     * @return
     */
    @Override
    //@GlobalTransactional(rollbackFor = Exception.class)
    public void wxRegister(WxRegisterDto dto) {
        //1.先获取参数，code，小程序ID，小程序秘钥
        String openId = wxTemplate.getOpenId(dto.getWxCode());

        //判断是否注册
        Driver driver = getDriver(openId);
        AssertUtil.isNotNull(driver,"已注册");


        //2.openid不存在就保存司机对象，并初始化关联对象，如钱包，设置，结算
        //String phone = wxTemplate.getPhone(dto.getPhoneCode());

        //driver = createDriver(openId,phone);
        walletService.createWallet(driver.getId());
        settingService.createSetting(driver.getId());
        summaryService.createSummary(driver.getId());

        //  3.远程保存login对象
        createLogin(driver);
        //返回结果
        log.info("微信注册成功");

    }

    /**
     * 司机工作台
     */
    @Override
    public WorkBenchDataVo selectWorkbenchDate() {
        //拿到司机信息
        Driver byId = super.getById(StpUtil.getLoginIdAsLong());
        //查看是否完成实名
        Boolean hasState = BitStatesUtils.hasState(byId.getBitState(), BitStatesUtils.OP_REAL_AUTHENTICATIONED);
        //查询司机的结算数据
        DriverSummary summary = summaryService.getById(byId.getId());

        return WorkBenchDataVo.builder()
                //司机实名状态
                .realAuthSuccess(hasState)
                //司机今日数据
                .summary(DriverSummaryVo.builder()
                        .driveDuration(summary.getDriveDuration())
                        .todayIncome(summary.getTodayIncome())
                        .todayTradeOrders(summary.getTodayTradeOrders())
                        .build())
                .build();

    }

    @Override
    public void online() {
        //开启司机接单，拿到司机ID，查询司机配置
        DriverSetting byId = settingService.getById(StpUtil.getLoginIdAsLong());
        DriverSettingBo settingBo = DriverSettingBo.builder()
                .rangeDistance(byId.getRangeDistance())
                .orderDistance(byId.getOrderDistance())
                .build();

        String format = String.format(Constants.Redis.DRIVER_SETTING, StpUtil.getLoginIdAsLong());
        redisTemplate.opsForValue().set(format, settingBo);

    }

    @Override
    public void offline() {
        //删除司机配置
        String format = String.format(Constants.Redis.DRIVER_SETTING, StpUtil.getLoginIdAsLong());
        redisTemplate.delete(format);
        //删除GEO
        redisTemplate.opsForGeo().remove(Constants.Redis.DRIVER_GEO,StpUtil.getLoginIdAsLong());
    }

    @Override
    public void cacheLocationGeo(LocationDto dto) {
        //保存司机坐标，用redisTemplate的GEO缓存
        redisTemplate.opsForGeo().add(
                Constants.Redis.DRIVER_GEO,
                new Point(dto.getLongitude(),dto.getLatitude()),
                StpUtil.getLoginIdAsLong()
        );

    }

    //根据openid查询司机
    private Driver getDriver(String openId) {
        //  2.判断；openid是否存在，如果存在就提示已注册
        LambdaQueryWrapper<Driver> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Driver::getOpenId, openId);
        //根据openid查询司机
        Driver driver = super.getOne(queryWrapper);
        return driver;
    }

    //保存Login
    private void createLogin(Driver driver){

        LoginFound login = LoginFound.builder()
                .phone(driver.getPhone())
                .openId(driver.getOpenId())
                //司机类型
                .type(Constants.Driver.TYPE_DRIVER)
                .username(driver.getPhone())
                .id(driver.getId())
                .build();

        JSONResult jsonResult = loginApi.create(login);
        AssertUtil.isTrue(jsonResult.isSuccess(),"远程保存Login失败");
    }


    //保存司机
    private Driver createDriver(String openid,String phone) {
        Driver driver = new Driver();
        driver.setOpenId(openid);
        driver.setPhone(phone);
        driver.setCreateTime(new Date());

        long bitState = BitStatesUtils.addState(0L, BitStatesUtils.OP_PHONE);
        driver.setBitState(bitState);

        super.save(driver);
        return driver;
    }
}
